/*
 * Copyright 2008-2009 Daniel Freitas
 * 
 * This file is part of Army Creator.
 * 
 * Army Creator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Army Creator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with Army Creator. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package com.googlecode.armycreator.datastore.test.integration

import com.googlecode.armycreator.datastore.test.PersistentDummy
import com.googlecode.armycreator.datastore.test.PersistentDummyDao
import com.googlecode.armycreator.datastore.test.TransactionService
import java.sql.Connection
import java.sql.Statement
import javax.sql.DataSource
import org.springframework.context.ApplicationContext
import org.testng.ITestContext
import org.testng.annotations.BeforeClass
import org.testng.annotations.BeforeMethod
import org.testng.annotations.Test

/**
 * @author <a href="mailto:daniel.mfreitas@gmail.com">Daniel Freitas</a>
 */
public class SpringAnnotationTransactionDemarcationIntegrationTest {

    private TransactionService transactionTestService = null
    private PersistentDummyDao persistentDummyDao = null

    private ApplicationContext applicationContext

    @BeforeClass (alwaysRun = true)
    public void setUpTest(ITestContext testContext) throws Exception {

        applicationContext = (ApplicationContext) testContext.getAttribute("applicationContext")
        transactionTestService = (TransactionService) applicationContext.getBean("transactionTestService")
        persistentDummyDao = (PersistentDummyDao) applicationContext.getBean("persistentDummyAdvisedDao")
    }

    @BeforeMethod (alwaysRun = true)
    public void populateData() throws Exception {
        DataSource dataSource = (DataSource) applicationContext.getBean("dataSource")
        Connection con = dataSource.getConnection()
        Statement statement = con.createStatement()
        URL filePath = getClass().getResource("/com/googlecode/armycreator/test-db-data.sql")
        statement.execute("RUNSCRIPT FROM '" + filePath + "'")
        statement.close()
        con.close()
    }

    /**
     * Tests if runtime exceptions occurred in one method rolls back all changes made by previous methods in the same
     * transaction.
     * <p>
     * Using a fake service that starts the transaction and delimits the transaction boundaries between multiple method
     * calls.
     */
    @Test (groups = ["integration", "fast"])
    public void testRuntimeExceptionRollBackChangesMadeByPreviousMethodsInSameTransaction() {

        PersistentDummy object1 = persistentDummyDao.findById(1L)
        PersistentDummy object2 = persistentDummyDao.findById(2L)

        object1.setFirstName("The wrong name")
        object2.setLastName("The wrong last name")

        try {
            transactionTestService.updateTwoObjectsAndThrowsRumtimeException(object1, object2)
        } catch (Exception e) {

        }

        PersistentDummy persistedObject1 = persistentDummyDao.findById(1L)
        PersistentDummy persistedObject2 = persistentDummyDao.findById(2L)

        assert persistedObject1.getFirstName().equals("Daniel"): String.format(
                "Expected firstName to remain the same (%s). It has been changed to %s.", expectedFirstName,
                persistedObject1.getFirstName())
        assert persistedObject2.getLastName().equals("Santos"): String.format(
                "Expected lastName to remain the same (%s). It has been changed to %s.", expectedLastName,
                persistedObject2.getLastName())
    }

    /**
     * Tests if checked exceptions occurred in one method does not roll back the changes made by previous methods in the
     * same transaction.
     * <p>
     * Using a fake service that starts the transaction and delimits the transaction boundaries between multiple method
     * calls.
     */
    @Test (groups = ["integration", "fast"])
    public void testCheckedExceptionCommitChangesMadeByPreviousMethodsInSameTransaction() {
        PersistentDummy object1 = persistentDummyDao.findById(1L)
        PersistentDummy object2 = persistentDummyDao.findById(2L)

        object1.setFirstName("The new name")
        object2.setLastName("The new last name")

        try {
            transactionTestService.updateTwoObjectsAndThrowsCheckedException(object1, object2);
        } catch (Exception e) {

        }

        PersistentDummy persistedObject1 = persistentDummyDao.findById(1L)
        PersistentDummy persistedObject2 = persistentDummyDao.findById(2L)

        assert persistedObject1.getFirstName().equals("The new name"): String.format(
                "Expected firstName to be updated to %s. It has been updated.", object1.getFirstName())
        assert persistedObject2.getLastName().equals("The new last name"): String.format(
                "Expected lastName to be updated to %s. It has been updated.", object2.getLastName())
    }

    /**
     * Tests if an checked exception occurred in one method rolls back all changes made by previous methods in the same
     * transaction if it has been annotated to do so.
     * <p>
     * Using a fake service that starts the transaction and delimits the transaction boundaries between multiple method
     * calls.
     */
    @Test (groups = ["integration", "fast"])
    public void testCheckedExceptionRollbackIfAnnotatedToDoSo() {

        PersistentDummy object1 = persistentDummyDao.findById(1L)
        PersistentDummy object2 = persistentDummyDao.findById(2L)

        object1.setFirstName("The wrong name")
        object2.setLastName("The wrong last name")

        try {
            transactionTestService.updateTwoObjectsAndThrowsCheckedExceptionAnnotatedForRollback(object1, object2)
        } catch (Exception e) {

        }

        PersistentDummy persistedObject1 = persistentDummyDao.findById(1L)
        PersistentDummy persistedObject2 = persistentDummyDao.findById(2L)

        assert persistedObject1.getFirstName().equals("Daniel"): String.format(
                "Expected firstName to remain the same (%s). It has been changed to %s.", expectedFirstName,
                persistedObject1.getFirstName())
        assert persistedObject2.getLastName().equals("Santos"): String.format(
                "Expected lastName to remain the same (%s). It has been changed to %s.", expectedLastName,
                persistedObject2.getLastName())
    }
}
